#ifndef __QE_SDTRACE_H__
#define __QE_SDTRACE_H__



#include "qe_def.h"
#include "qe_queue.h"
#include "qe_buffer.h"



/**
 * Sequence Data Trace Record Struct
 */
typedef struct 
{
    /* Start marks, setting in initialization fixed to 'sdtrc-start' */
    char start_mark[16];

    /* Recorder version major.minor.patch */
    qe_u32 version;

    /* Recorder size in bytes */
    qe_u32 size;

    /* Number of data recorded */
    qe_u32 num_datas;

    /* Number of recorded blocks */
    qe_u32 num_recorded_blocks;

    /* The buffer size, in number of datas */
    qe_u32 max_datas;

    /* Block size, erase unit */
    qe_u32 block_size;

    /* Number of used blocks */
    qe_u32 num_blocks;

    /* Number of blocks align datas */
    qe_u32 num_blocks_align_datas;

    /* Serialize counter */
    qe_u32 serialize_count;

    /* The buffer index, where to write next */
    qe_u32 next_free;

    /* 1 if the buffer is full */
    qe_u32 is_full;

    /* 1 if the recorder has been started */
    qe_u32 is_active;

    /* 'SOFD' */
    qe_u32 data_start_mark;

    qe_u8 datas[0];

    /* 'EOFD' */
    qe_u32 data_end_mark;

    /* End marks, setting in initialization fixed to 'sdtrc-end' */
    char end_mark[16];
} qe_sdtrace_meta;

typedef enum {
    QE_SDTRC_STRM_RB = 0,
    QE_SDTRC_STRM_WB,
} qe_sdtrace_stream_mode;

struct qe_seqdata_trace_stream;
typedef struct qe_seqdata_trace_stream qe_sdtrace_stream;

typedef struct qe_seqdata_trace_stream
{
    qe_ret (*open)  (qe_sdtrace_stream *stream, qe_u8 mode, qe_uint size);
    qe_ret (*close) (qe_sdtrace_stream *stream);
    qe_int (*read)  (qe_sdtrace_stream *stream, qe_ptr buf, qe_uint len);
    qe_int (*write) (qe_sdtrace_stream *stream, qe_const_ptr buf, qe_uint len);
    void *user;
} qe_sdtrace_stream;

typedef struct {
    qe_u32 chunk_size;
    qe_u32 chunks_per_block;
    qe_u32 start_block;
    qe_u32 end_block;
    qe_u32 num_cache_blocks;
} qe_sdtrace_blockio_config;

struct qe_seqdata_trace_blockio;
typedef struct qe_seqdata_trace_blockio qe_sdtrace_blockio;

typedef struct qe_seqdata_trace_blockio {
    
    qe_ret (*init)        (qe_sdtrace_blockio *bio);
    qe_ret (*block_erase) (qe_sdtrace_blockio *bio, qe_u32 block);
    qe_ret (*chunk_read)  (qe_sdtrace_blockio *bio, qe_u32 chunk, qe_ptr data, qe_uint len);
    qe_ret (*chunk_write) (qe_sdtrace_blockio *bio, qe_u32 chunk, qe_const_ptr data, qe_uint len);
    
    qe_ptr user;
    
    qe_sdtrace_blockio_config config;

    qe_u32 chunk_size;
    qe_u32 block_size;
    qe_u32 start_block;
    qe_u32 end_block;
    qe_u32 meta_block;
    qe_u32 meta_chunk;
    qe_u32 num_blocks;
    qe_u32 num_data_blocks;
    qe_u32 num_unused_blocks;
    qe_u32 num_cache_blocks;
    qe_u32 num_cache_chunks;
    qe_u32 num_cache_datas;
} qe_sdtrace_blockio;

/**
 * Tracer struct
 */
typedef struct
{
    //qe_sdtrace_stream *stream;

    qe_sdtrace_blockio *bio;

    qe_ringq *ring;

    qe_sdtrace_meta meta;

    qe_u32 data_size;
    qe_u32 meta_size;

    qe_bool is_initialized;
} qe_sdtrace;

qe_sdtrace *qe_sdtrace_new(qe_uint size, qe_sdtrace_blockio *bio);

qe_ret qe_sdtrace_record_datas(qe_sdtrace *trace, qe_const_ptr data, qe_uint num);

qe_ret qe_sdtrace_load(qe_sdtrace *trace);

void qe_sdtrace_destroy(qe_sdtrace *trace);

void qe_sdtracer_destroy(qe_sdtrace *trace);



#endif /* __QE_SDTRACE_H__ */